function f_logging()
{
    #日志函数, 接收五个参数, 其中第一个是必选, 其余四个是可选
    #第一个表示日志内容
    #第二个表示日志级别, 包含脚本名, 函数名(包含父函数), 行号等信息
    #第三个表示是否需要回车(line0|line1|line2, line0表示不需要换行, 即记录完日志后不换行, line1表示需要换行, 这是正常的选项), line2表示两个换行，即前后需要一个换行
    #第四个控制退出/返回 现在仅支持exit0 exit1 return0 return1这四个状态, 分别对应正常退出, 异常退出, 正常返回, 异常返回
    #第五个控制是否写到日志文件, 接收一个日志路径，可以为空表示不写文件

    #f_logging "这是一个测试日志" "$(eval echo ${log_addr}):INFO" "line1" "return0" "/path/xxx.log"

    [ -z "${1}" ] && return 1

    declare pfun_name fun_name log_mode log_info enter_mark enter_opt exit_opt line_num localhost_ip tee_mark

    #获取本机ip地址(其中一块网卡)
    localhost_ip="$(/sbin/ip a 2>/dev/null|grep inet|grep brd|grep scope|awk '{print $2}'|awk -F'/' 'NR==1{print $1}')" || true

    log_info="${1}"     #日志信息
    file_name="$(awk -F: '{$0=$1;FS="/";gsub("^/","",$0);print (NF>=2?$(NF-1)"/"$NF:$NF)}' <<< "${2}")"    #文件名
    fun_name="$(awk -F: '{print $2}' <<< "${2}")"     #函数名
    [ -z "${fun_name}" ] && fun_name="${FUNCNAME[1]}" #没指定就默认以本函数名的父函数

    pfun_name="$(awk -F: '{print $3}' <<< "${2}")"    #函数名被调用的函数
    line_num="$(awk -F: '{print $4}' <<< "${2}")"     #文件行号
    log_mode="$(awk -F: '{print $5}' <<< "${2}")"     #日志级别
    [ -z "${line_num}" ] && line_num="NULL"           #没指定行号就置为空
    [ -z "${log_mode}" ] && log_mode="REMAIND"        #没指定日志级别就使用默认值, 即提示信息

    enter_opt="${3}"    #日志行前后是否需要空行

    exit_opt="${4}"     #是否需要退出任务
    [ -z "${exit_opt}" ] && exit_opt="return0"        #没指定退出就使用默认值, 即正常退出

    log_path="${5}"     #是否需要写到日志, 这里接收一个日志路径

    #定义一个关联数组, 预定义各个日志级别的显示颜色
    declare -A mode_color
    mode_color=(
        ["ERROR"]="\033[31m" 
        ["INFO"]="\033[32m"
        ["WARN"]="\033[33m" 
        ["COMMAND"]="\033[34m" 
        ["DEBUG"]="\033[37m" 
    )

    #定义一个关联数组, 预定义各个退出/返回状态的具体操作
    declare -A exit_state
    exit_state=(
        ["exit0"]="exit 0"
        ["exit1"]="exit 1"
        ["return0"]="return 0"
        ["return1"]="return 1"
    )

    echo -en "${mode_color["${log_mode}"]}"

    #是否需要前后空行
    enter_mark=""        #表示回车的动作, 初始化为空
    [ "${enter_opt}x" == "line2x" ] && enter_mark="\n"

    [ -z "${pfun_name}" ] && pfun_name="main"
    [ -z "${fun_name}" ] && fun_name="main"

    log_info="[ $(date "+%F %T") ] [ ${log_mode} ] [ ${localhost_ip} ] [ ${file_name} ] [ ${pfun_name} --> ${fun_name}:${line_num} ] [ ${log_info} ]"

    #是否需要写到文件
    tee_mark="tee"
    [ -f "${log_path}" ] && tee_mark="tee -a ${log_file}"

    echo -e "${enter_mark}${log_info}${enter_mark}"|${tee_mark}
    echo -n|${tee_mark}

    eval ${exit_state["${exit_opt}"]}
}